﻿using Castle.DynamicProxy;
using Microsoft.Extensions.Logging;
using System;
using System.Diagnostics;
using System.Reflection;
using System.Threading.Tasks;
using XfTechOAWeb.Data.Base;
using XfTechOAWeb.Infrastructure.Attributes;

namespace XfTechOAWeb.Infrastructure.Interceptors
{
    /// <summary>
    /// 事务AOP处理
    /// </summary>
    public class TransactionAOP : IInterceptor
    {
        private readonly IUnitOfWorkManage _unitOfWorkManage;
        private readonly ILogger<TransactionAOP> _logger;

        /// <summary>
        /// 构造方法
        /// </summary>
        /// <param name="logger"></param>
        public TransactionAOP(ILogger<TransactionAOP> logger, IUnitOfWorkManage unitOfWorkManage = null)
        {
            _logger = logger;
            _unitOfWorkManage = unitOfWorkManage;
        }

        /// <summary>
        /// 拦截器执行方法
        /// </summary>
        /// <param name="invocation"></param>
        public void Intercept(IInvocation invocation)
        {
            var method = invocation.MethodInvocationTarget ?? invocation.Method;
            //对当前方法的特性验证
            //如果需要验证
            if (method.GetCustomAttribute<UseTranAttribute>(true) != null)
            {
                try
                {
                    _unitOfWorkManage.BeginTran();   //开启事务

                    invocation.Proceed();     //执行被拦截方法

                    // 异步获取异常，先执行
                    if (IsAsyncMethod(invocation.Method))
                    {
                        var result = invocation.ReturnValue;
                        if (result is Task)
                        {
                            Task.WaitAll(result as Task);
                        }
                    }

                    _unitOfWorkManage.CommitTran();  // 提交事务
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex.ToString());
                    _unitOfWorkManage.RollbackTran(); //回滚事务
                    throw;
                }
            }
            else
            {
                invocation.Proceed(); //直接执行被拦截方法
            }
        }

        /// <summary>
        /// 判断是否为异步方法
        /// </summary>
        /// <param name="method"></param>
        /// <returns></returns>
        public static bool IsAsyncMethod(MethodInfo method)
        {
            return (
                method.ReturnType == typeof(Task) ||
                (method.ReturnType.IsGenericType && method.ReturnType.GetGenericTypeDefinition() == typeof(Task<>))
            );
        }
    }
}
